package controllers

import (
	"alarmservice/com"
	"alarmservice/model"
	"alarmservice/service"
	"sort"
	"strconv"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/validation"
)

//Login处理
type ProjectController struct {
	baseController
	Project     *model.Project
	ProjectUser *model.AdminUser
	IsAdmin     bool
}

func (c *ProjectController) NextPrepare() {
	c.NeedLogin = true
	c.IsAdmin = false

	c.UseLayout()

	projectId := c.Ctx.Input.Param(":pid")

	if projectId != "" {
		projectIdInt64, err := strconv.ParseInt(projectId, 10, 64)
		if err == nil {
			c.initProject(projectIdInt64)
		}
	}

	c.Data["IsAdmin"] = c.IsAdmin
}

//加载项目相关的面包屑导航
func (c *ProjectController) AddProjectBreadCrumb() {
	listSubMenu := c.GetString("listsubmenu", "project")
	c.Data["SubMenu"] = listSubMenu

	if listSubMenu == "project_my" {
		c.AddBreadCrumb("我的项目", "/project/my")
	} else {
		c.AddBreadCrumb("项目列表", "/project")
	}

	c.AddBreadCrumb(c.Project.Title, "/project/"+strconv.FormatInt(c.Project.Id, 10))
}

func (c *ProjectController) initProject(id int64) bool {
	project := &model.Project{}
	err := model.GetById(id, project)

	if err != nil {
		return false
	}
	c.Project = project
	c.Data["Project"] = project

	//查询project用户ID
	user := &model.AdminUser{}

	err = model.GetById(project.UserId, user)

	if err != nil {
		return false
	}

	c.ProjectUser = user
	c.Data["ProjectUser"] = user
	if c.AdminUser.Id == user.Id {
		c.IsAdmin = true
	}

	return true
}

func (c *ProjectController) PageMyList() {
	total, err := model.CountByExample(&model.Project{Status: model.StatusNormal, UserId: c.AdminUser.Id})
	if err != nil {
		c.Abort("500")
		return
	}

	c.AddBreadCrumb("我的项目", "/project/my")

	//设置分页
	paginator := c.SetPaginator(20, total)

	projects := make(model.MapProject)
	model.Orm.Where("user_id=?", c.AdminUser.Id).OrderBy("id desc").Limit(int(paginator.Nums()), paginator.Offset()).Find(&projects)

	if len(projects) > 0 {
		//填充额外数据
		c.paddingDataForProjectList(projects)
	}

	c.Data["SubMenu"] = "project_my"

	c.TplName = "project/list.tpl"
}

func (c *ProjectController) PageList() {
	total, err := model.CountByExample(&model.FollowProject{UserId: c.AdminUser.Id})
	if err != nil {
		beego.Error(err)
		c.Abort("500")
		return
	}

	c.AddBreadCrumb("项目列表", "/project")

	//设置分页
	paginator := c.SetPaginator(20, total)

	followProjects := make(model.SliceFollowProject, 0)
	err = model.Orm.Where("user_id=?", c.AdminUser.Id).OrderBy("create_time desc").Limit(paginator.PerPageNums, paginator.Offset()).Find(&followProjects)
	if err != nil {
		beego.Error(err)
		c.Abort("500")
		return
	}

	projects, err := model.GetProjectFromProjectIdContainer(followProjects)
	if len(projects) > 0 {
		//填充额外数据
		c.paddingDataForProjectList(projects)
	}

	c.Data["SubMenu"] = "project"

	c.TplName = "project/list.tpl"
}

func (c *ProjectController) paddingDataForProjectList(projects model.MapProject) {

	projectIds := projects.GetProjectIds()

	adminUsers, auerr := model.GetUserFromUserIdContainer(projects)
	if auerr != nil {
		beego.Error(auerr)
		c.Abort("500")
		return
	}

	//根据开始时间和结束时间查询
	warningNums, err := service.GetWarningNumsGroupByProject(projectIds, time.Now().Add(-86400*time.Second), 86400)
	tracingNums, terr := service.GetTracingNumsGroupByProject(projectIds)
	tracingEnabledNums, teerr := service.GetTracingEnableNumsGroupByProject(projectIds)
	userNums, uerr := service.GetUserNumsGroupByProject(projectIds)
	if err != nil || terr != nil || teerr != nil || uerr != nil {
		c.Abort("500")
		return
	}
	sort.Sort(sort.Reverse(model.IdList(projectIds)))

	c.Data["ProjectIds"] = projectIds
	c.Data["Projects"] = projects
	c.Data["WarningNums"] = warningNums
	c.Data["TracingNums"] = tracingNums
	c.Data["TracingEnabledNums"] = tracingEnabledNums
	c.Data["UserNums"] = userNums
	c.Data["Users"] = adminUsers
}

func (c *ProjectController) PageCreate() {
	c.Data["IsCreate"] = true

	//创建项目
	if c.Ctx.Request.Method == "GET" {
		c.createGet()
	} else {
		c.createPost()
	}
}

func (c *ProjectController) createGet() {
	postProjectMap, ok := c.Data["PostProjectMap"]
	if !ok {
		if c.Ctx.Request.Method == "POST" {
			c.Data["PostProjectMap"] = c.Data["POST"]
		} else {
			c.Data["PostProjectMap"] = make(map[string]interface{})
		}
	} else {
		c.Data["PostProjectMap"] = postProjectMap
	}

	c.TplName = "project/edit.tpl"
}

func (c *ProjectController) createPost() {
	valid := validation.Validation{}

	postProject := model.NewProject()

	if err := c.ParseForm(postProject); err != nil {
		c.Data["Errors"] = err.Error()
		c.createGet()
		return
	}

	postProjectMap := model.Obj2Map(*postProject)

	c.Data["PostProjectMap"] = postProjectMap

	b, err := valid.Valid(postProject)

	if err != nil {
		c.Abort("500")
	}

	if !b {
		mapFormErrs := com.ValidErrorToMapByField(valid.Errors)
		c.SetFormErrsToJson(mapFormErrs)
		c.createGet()
		return
	}

	postProject.UserId = c.AdminUser.Id

	err = model.Insert(postProject)
	if err != nil {
		c.Abort("500")
		return
	}

	//加入项目关联信息 如果失败，在我的项目中点击项目详情时，会查找并尝试重新建立关系
	_ = model.Insert(&model.FollowProject{ProjectId: postProject.Id, UserId: c.AdminUser.Id})

	//成功跳转
	c.Redirect("/project/"+strconv.FormatInt(postProject.Id, 10), 302)
	return
}

func (c *ProjectController) PageUpdate() {
	c.Data["IsCreate"] = false
	if c.Project == nil || c.Project.Id <= 0 {
		c.Abort("404")
		return
	}

	if c.Ctx.Request.Method == "GET" {
		c.updateGet()
	} else {
		c.updatePost()
	}
}

func (c *ProjectController) updateGet() {
	_, ok := c.Data["PostProjectMap"]
	if !ok {
		c.Data["PostProjectMap"] = model.Obj2Map(*c.Project)
	}

	//都是显示内容而已
	c.createGet()
	return
}

func (c *ProjectController) updatePost() {
	if !c.IsAdmin {
		c.Abort("403")
		return
	}

	valid := validation.Validation{}

	postProject := &model.Project{}

	if err := c.ParseForm(postProject); err != nil {
		c.Data["Errors"] = err.Error()
		c.createGet()
		return
	}

	postProjectMap := model.Obj2Map(*postProject)

	c.Data["PostProjectMap"] = postProjectMap

	b, err := valid.Valid(postProject)

	if err != nil {
		c.Abort("500")
	}

	if !b {
		mapFormErrs := com.ValidErrorToMapByField(valid.Errors)
		c.SetFormErrsToJson(mapFormErrs)
		c.updateGet()
		return
	}

	err = model.UpdateById(c.Project.Id, postProject)
	if err != nil {
		c.Abort("500")
		return
	}

	//成功跳转
	c.Redirect("/project/"+strconv.FormatInt(c.Project.Id, 10), 302)
	return
}

func (c *ProjectController) PageWarningList() {
	c.AddProjectBreadCrumb()

	total, err := model.CountByExample(&model.Warning{ProjectId: c.Project.Id})

	if err != nil {
		c.Abort("500")
		return
	}

	paginator := c.SetPaginator(20, total)
	warnings := make(model.MapWarning)
	err = model.Orm.Where("project_id=?", c.Project.Id).OrderBy("create_time desc").Limit(paginator.PerPageNums, paginator.Offset()).Find(&warnings)
	if err != nil {
		c.Abort("500")
		return
	}

	warningIds := warnings.GetWarningIds()
	sort.Sort(sort.Reverse(model.IdList(warningIds)))
	c.Data["Warnings"] = warnings
	c.Data["WarningIds"] = warningIds

	tracings, err := model.GetTracingFromTracingIdContainer(warnings)
	if err != nil {
		c.Abort("500")
		return
	}
	c.Data["Tracings"] = tracings

	c.TplName = "project/warnings.tpl"
}

func (c *ProjectController) PageDetail() {
	if c.Project == nil || c.Project.Id <= 0 {
		c.Abort("404")
		return
	}

	c.AddProjectBreadCrumb()

	//创建项目时，为非事务提交两条记录，在这里可以保证数据的完整性
	if c.Project.UserId == c.AdminUser.Id {
		//检查关联关系是否存在
		followProject := &model.FollowProject{ProjectId: c.Project.Id, UserId: c.AdminUser.Id}
		if !model.IsExist(followProject) {
			model.Insert(followProject)
		}
	}

	//获取最近的报警记录
	warnings := make(model.MapWarning)

	err := model.Orm.Where("project_id=?", c.Project.Id).Limit(20, 0).OrderBy("create_time desc").Find(&warnings)

	if err != nil {
		c.Abort("500")
		return
	}

	c.Data["Warnings"] = warnings
	if len(warnings) > 0 {
		warningIds := warnings.GetWarningIds()
		sort.Sort(sort.Reverse(model.IdList(warningIds)))
		c.Data["WarningIds"] = warningIds
	} else {
		c.Data["WarningIds"] = []int64{}
	}

	//获取监控点详细信息
	tracings, err := model.GetTracingFromTracingIdContainer(warnings)
	if err != nil {
		c.Abort("500")
	}
	c.Data["Tracings"] = tracings

	//获取关注项目的人
	followProjects := make(model.SliceFollowProject, 0)

	err = model.Orm.Where("project_id=?", c.Project.Id).Find(&followProjects)

	if err != nil {
		c.Abort("500")
		return
	}

	users, err := model.GetUserFromUserIdContainer(followProjects)
	if err != nil {
		c.Abort("500")
		return
	}
	c.Data["FollowUsers"] = users

	projectIdsParam := make([]int64, 1)
	projectIdsParam = append(projectIdsParam, c.Project.Id)
	//获取监控点数量，获取最近24小时报警量
	warningNums, err := service.GetWarningNumsGroupByProject(projectIdsParam, time.Now().Add(-86400*time.Second), 86400)

	tracingNums, terr := service.GetTracingNumsGroupByProject(projectIdsParam)
	if err != nil || terr != nil {
		c.Abort("500")
		return
	}

	var warningNum, tracingNum int64

	warningNumStruct, ok := warningNums[c.Project.Id]
	if ok {
		warningNum = warningNumStruct.Total
	}

	tracingNumStruct, ok := tracingNums[c.Project.Id]
	if ok {
		tracingNum = tracingNumStruct.Total
	}

	c.Data["WarningNum"] = warningNum
	c.Data["TracingNum"] = tracingNum

	c.TplName = "project/detail.tpl"
}

func (c *ProjectController) PageAjaxRemoveUser() {
	userId, _ := c.GetInt64("uid", 0)
	if userId == 0 {
		c.returnJson(com.ApiUnknowFailed("need params"))
		return
	}

	if userId == c.ProjectUser.Id {
		c.returnJson(com.ApiUnknowFailed("can't remove self"))
		return
	}

	if !c.IsAdmin {
		c.returnJson(com.ApiUnknowFailed("auth error!"))
		return
	}

	//是自己项目,准备删除
	err := model.DeleteByExample(model.FollowProject{ProjectId: c.Project.Id, UserId: userId})
	if err != nil {
		c.returnJson(com.ApiUnknowFailed("delete error!"))
		return
	}

	c.returnJson(com.ApiSucc(""))
	return
}

/*
接收username,name,uid参数
查询uid是否和username和name匹配作出相关判断
*/
func (c *ProjectController) PageAjaxAddUser() {
	uid, _ := c.GetInt64("uid", 0)
	username := c.GetString("username")
	name := c.GetString("name")

	if uid <= 0 {
		c.returnJson(com.ApiUnknowFailed("params error!"))
		return
	}

	user, err := model.GetAdminUserById(uid)

	if err != nil {
		c.returnJson(com.ApiUnknowFailed("get user info err!"))
		return
	}

	if user.Name != name || user.Username != username {
		c.returnJson(com.ApiUnknowFailed("params not match uid"))
		return
	}

	if !c.IsAdmin {
		c.returnJson(com.ApiUnknowFailed("auth error!"))
		return
	}

	//检查是否已经在follow列表中 本来就是主键，不需要再检查了，自己会出错
	fp := model.FollowProject{}
	fp.ProjectId = c.Project.Id
	fp.UserId = uid
	err = model.Insert(fp)
	if err != nil {
		c.returnJson(com.ApiUnknowFailed("add user error!"))
		return
	} else {
		c.returnJson(com.ApiSucc(""))
		return
	}
}

//检查是否是该项目的跟随者
func (c *ProjectController) IsFollower() bool {
	if c.IsAdmin {
		return true
	}

	followUser := model.FollowProject{UserId: c.Uid, ProjectId: c.Project.Id}
	err := model.GetByExample(&followUser)
	if err != nil {
		return false
	}

	return true
}
